package nio.base.socket.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class WebServer {
	public static void main(String[] args) {
		try {
			ServerSocketChannel ssc = ServerSocketChannel.open();
			ssc.socket().bind(new InetSocketAddress("192.168.31.198", 8000));
			ssc.configureBlocking(false);

			Selector selector = Selector.open();
			// 注册 channel，作为服务端唯一感兴趣的事件是 Accept
			ssc.register(selector, SelectionKey.OP_ACCEPT);

			ByteBuffer readBuff = ByteBuffer.allocate(1024);

			while (true) {
				int nReady = selector.select();
				if (nReady == 0)
					continue;
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> it = keys.iterator();
				while (it.hasNext()) {
					SelectionKey key = it.next();
					it.remove();
					// 处理OP_ACCEPT事件
					if (key.isAcceptable()) {
						SocketChannel socketChannel = ssc.accept();
						socketChannel.configureBlocking(false);
						System.out.println("来自" + socketChannel.getRemoteAddress() + "的新连接接入");
						// 把连接注册到selector上,指定这个channel只对读操作感兴趣
						socketChannel.register(selector, SelectionKey.OP_READ);
						continue;
					}

					// 处理OP_READ事件
					if (key.isReadable()) {
						SocketChannel socketChannel = (SocketChannel) key.channel();
						readBuff.clear();
						if (socketChannel.read(readBuff) == -1) {
							key.cancel();
							continue;
						}
						readBuff.flip();
						System.out.println("received : " + new String(readBuff.array()));
						key.interestOps(SelectionKey.OP_WRITE);
						continue;
					}

					// 处理OP_WRITE事件
					if (key.isWritable()) {
						SocketChannel socketChannel = (SocketChannel) key.channel();
						socketChannel.write(ByteBuffer.wrap("received".getBytes()));
						key.interestOps(SelectionKey.OP_READ);
						continue;
					}

				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}